package recommend;


import javafx.util.Pair;
import segmenter.ChineseSegmenter;
import segmenter.ChineseSegmenterImpl;
import tf_idf.TF_IDF;
import util.StockSorterImpl;
import util.StockSorter;
import vo.StockInfo;
import vo.UserInterest;

import java.util.*;

public class RecommenderImpl implements Recommender {
    /**
     * this function need to calculate stocks' content similarity,and return the similarity matrix
     *
     * @param stocks stock info
     * @return similarity matrix
     */
    @Override
    public double[][] calculateMatrix(StockInfo[] stocks) {
        //TODO: write your code here
        for (int i=0;i<stocks.length;i++) {
            stocks[i].setIndex("content");
        }
        double[][] Matrix = new double[stocks.length][stocks.length];
        for (int i=0;i<stocks.length;i++) {
            Matrix[i][i]=1;
        }
        for (int p=0;p<stocks.length;p++) {
            for (int q=stocks.length-1;q>p;q--) {
                Matrix[p][q]=calculateSimilarity(stocks[p],stocks[q],stocks);
                Matrix[q][p]=Matrix[p][q];
            }
        }
        return Matrix;
    }

    /**
     * this function need to recommend the most possibility stock number
     *
     * @param matrix       similarity matrix
     * @param userInterest user interest
     * @return commend stock number
     */
    @Override
    public double[][] recommend(double[][] matrix, UserInterest[] userInterest) {
        //TODO: write your code here
        double[][] Recommend = new double[userInterest.length][10];
        for (int i=0;i<userInterest.length;i++) {
            List<Integer> interestIndex = new ArrayList<>();
            List<Integer> disinterestIndex = new ArrayList<>();
            for (int j=0;j<userInterest[i].getInterest().length;j++) {
                if (userInterest[i].getInterest()[j]==1) {
                    interestIndex.add(j);
                }
                else {
                    disinterestIndex.add(j);
                }
            }

            Pair<Integer,Double>[] pairs = new Pair[disinterestIndex.size()];
            for (int p=0;p<disinterestIndex.size();p++) {
                double like = 0;
                for (int q = 0; q < interestIndex.size(); q++) {
                    like += matrix[p][q];
                }
                pairs[p] = new Pair<Integer, Double>(p, like);
            }

            pairs = new StockSorterImpl().sortInfo(pairs);

            for (int x=0;x<10;x++) {
                Recommend[i][x]=new Double(pairs[x].getKey()+1);
            }
        }
        return Recommend;
    }

    @Override
    public double calculateSimilarity(StockInfo stock1, StockInfo stock2, StockInfo[] stocks) {
        ChineseSegmenterImpl segmenter = new ChineseSegmenterImpl();
        List<String> keyword1 = segmenter.getKeyWordsFromStockInfo(stock1,stocks);
        List<String> keyword2 = segmenter.getKeyWordsFromStockInfo(stock2,stocks);
        for (int i=0;i<keyword2.size();i++) {
            if (!keyword1.contains(keyword2.get(i))) {
                keyword1.add(keyword2.get(i));
            }
        }
        double[]Vector1=new double[keyword1.size()];
        double[]Vector2=new double[keyword1.size()];

        List<String> normalword1 = segmenter.getWordsFromContent(stock1);
        List<String> normalword2 = segmenter.getWordsFromContent(stock2);

        tfVector(Vector1,normalword1,keyword1);
        tfVector(Vector2,normalword2,keyword1);


        return cosine(Vector1,Vector2);
    }

    @Override
    public double[] tfVector(double[] vector,List<String> normalword,List<String> keyword) {
        int freq;
        for (int i=0;i<keyword.size();i++) {
            freq=0;
            for (int j=0;j<normalword.size();j++) {
                if (keyword.get(i)==normalword.get(j)) {
                    freq++;
                    vector[i]=freq;
                }
            }
        }
        return vector;
    }

    @Override
    public double cosine(double[] v1, double[] v2) {
        double numerator=0;
        double denominator;
        double part1=0,part2=0;
        for (int i=0;i<v1.length;i++) {
            numerator += v1[i]*v2[i];
        }
        for (int j=0;j<v1.length;j++) {
            part1 +=Math.pow(v1[j],2);
            part2 +=Math.pow(v2[j],2);
        }
        denominator = Math.sqrt(part1)*Math.sqrt(part2);
        if (denominator!=0) {
            return Math.cos(numerator/denominator);
        }
        else {
            return 0;
        }
    }
}
